package com.carrental.search.repository;

import com.carrental.search.model.document.VehicleDocument;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Repository;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 车辆索引文档的降级存储库实现
 * 当Elasticsearch不可用时使用，提供基本的内存存储功能
 */
@Slf4j
@Repository
@ConditionalOnProperty(name = "spring.elasticsearch.repositories.enabled", havingValue = "false")
public class VehicleRepositoryFallback implements VehicleRepository {

    // 使用内存存储模拟Elasticsearch
    private final Map<Long, VehicleDocument> vehicleStore = new ConcurrentHashMap<>();

    @Override
    public Page<VehicleDocument> searchSimilar(VehicleDocument entity, String[] fields, Pageable pageable) {
        log.warn("使用降级VehicleRepository: searchSimilar - 返回空结果");
        return new PageImpl<>(Collections.emptyList(), pageable, 0);
    }

    @Override
    public List<VehicleDocument> findByBrand(String brand) {
        log.warn("使用降级VehicleRepository: findByBrand");
        return filterByBrand(brand);
    }

    @Override
    public List<VehicleDocument> findByModel(String model) {
        log.warn("使用降级VehicleRepository: findByModel");
        return filterByModel(model);
    }

    @Override
    public List<VehicleDocument> findByType(String type) {
        log.warn("使用降级VehicleRepository: findByType");
        return filterByType(type);
    }

    @Override
    public List<VehicleDocument> findByStoreId(Long storeId) {
        log.warn("使用降级VehicleRepository: findByStoreId");
        return filterByStoreId(storeId);
    }

    @Override
    public List<VehicleDocument> findByStatus(Integer status) {
        log.warn("使用降级VehicleRepository: findByStatus");
        return filterByStatus(status);
    }

    @Override
    public List<VehicleDocument> findByDailyRentBetween(BigDecimal minDailyRent, BigDecimal maxDailyRent) {
        log.warn("使用降级VehicleRepository: findByDailyRentBetween");
        return filterByDailyRentBetween(minDailyRent, maxDailyRent);
    }

    @Override
    public List<VehicleDocument> findBySeats(Integer seats) {
        log.warn("使用降级VehicleRepository: findBySeats");
        return filterBySeats(seats);
    }

    @Override
    public List<VehicleDocument> findByKeyword(String keyword) {
        log.warn("使用降级VehicleRepository: findByKeyword");
        return filterByKeyword(keyword);
    }

    @Override
    public List<VehicleDocument> findByRecommended(Boolean recommended) {
        log.warn("使用降级VehicleRepository: findByRecommended");
        return filterByRecommended(recommended);
    }

    @Override
    public List<VehicleDocument> findByRatingBetween(Float minRating, Float maxRating) {
        log.warn("使用降级VehicleRepository: findByRatingBetween");
        return filterByRatingBetween(minRating, maxRating);
    }

    @Override
    public List<VehicleDocument> findByYearBetween(Integer minYear, Integer maxYear) {
        log.warn("使用降级VehicleRepository: findByYearBetween");
        return filterByYearBetween(minYear, maxYear);
    }

    @Override
    public Iterable<VehicleDocument> findAll(Sort sort) {
        log.warn("使用降级VehicleRepository: findAll(Sort)");
        return vehicleStore.values();
    }

    @Override
    public Page<VehicleDocument> findAll(Pageable pageable) {
        log.warn("使用降级VehicleRepository: findAll(Pageable)");
        return Page.empty(pageable);
    }

    @Override
    public <S extends VehicleDocument> S save(S entity) {
        log.warn("使用降级VehicleRepository: save");
        vehicleStore.put(entity.getId(), entity);
        return entity;
    }

    @Override
    public <S extends VehicleDocument> Iterable<S> saveAll(Iterable<S> entities) {
        log.warn("使用降级VehicleRepository: saveAll");
        entities.forEach(entity -> vehicleStore.put(entity.getId(), entity));
        return entities;
    }

    @Override
    public Optional<VehicleDocument> findById(Long id) {
        log.warn("使用降级VehicleRepository: findById");
        return Optional.ofNullable(vehicleStore.get(id));
    }

    @Override
    public boolean existsById(Long id) {
        log.warn("使用降级VehicleRepository: existsById");
        return vehicleStore.containsKey(id);
    }

    @Override
    public Iterable<VehicleDocument> findAll() {
        log.warn("使用降级VehicleRepository: findAll");
        return vehicleStore.values();
    }

    @Override
    public Iterable<VehicleDocument> findAllById(Iterable<Long> ids) {
        log.warn("使用降级VehicleRepository: findAllById");
        List<VehicleDocument> result = new ArrayList<>();
        ids.forEach(id -> {
            VehicleDocument doc = vehicleStore.get(id);
            if (doc != null) {
                result.add(doc);
            }
        });
        return result;
    }

    @Override
    public long count() {
        log.warn("使用降级VehicleRepository: count");
        return vehicleStore.size();
    }

    @Override
    public void deleteById(Long id) {
        log.warn("使用降级VehicleRepository: deleteById");
        vehicleStore.remove(id);
    }

    @Override
    public void delete(VehicleDocument entity) {
        log.warn("使用降级VehicleRepository: delete");
        vehicleStore.remove(entity.getId());
    }

    @Override
    public void deleteAllById(Iterable<? extends Long> ids) {
        log.warn("使用降级VehicleRepository: deleteAllById");
        ids.forEach(vehicleStore::remove);
    }

    @Override
    public void deleteAll(Iterable<? extends VehicleDocument> entities) {
        log.warn("使用降级VehicleRepository: deleteAll(Iterable)");
        entities.forEach(entity -> vehicleStore.remove(entity.getId()));
    }

    @Override
    public void deleteAll() {
        log.warn("使用降级VehicleRepository: deleteAll");
        vehicleStore.clear();
    }

    // 辅助方法
    private List<VehicleDocument> filterByBrand(String brand) {
        List<VehicleDocument> result = new ArrayList<>();
        vehicleStore.values().forEach(doc -> {
            if (doc.getBrand() != null && doc.getBrand().equals(brand)) {
                result.add(doc);
            }
        });
        return result;
    }

    private List<VehicleDocument> filterByModel(String model) {
        List<VehicleDocument> result = new ArrayList<>();
        vehicleStore.values().forEach(doc -> {
            if (doc.getModel() != null && doc.getModel().equals(model)) {
                result.add(doc);
            }
        });
        return result;
    }

    private List<VehicleDocument> filterByType(String type) {
        List<VehicleDocument> result = new ArrayList<>();
        vehicleStore.values().forEach(doc -> {
            if (doc.getType() != null && doc.getType().equals(type)) {
                result.add(doc);
            }
        });
        return result;
    }

    private List<VehicleDocument> filterByStoreId(Long storeId) {
        List<VehicleDocument> result = new ArrayList<>();
        vehicleStore.values().forEach(doc -> {
            if (doc.getStoreId() != null && doc.getStoreId().equals(storeId)) {
                result.add(doc);
            }
        });
        return result;
    }

    private List<VehicleDocument> filterByStatus(Integer status) {
        List<VehicleDocument> result = new ArrayList<>();
        vehicleStore.values().forEach(doc -> {
            if (doc.getStatus() != null && doc.getStatus().equals(status)) {
                result.add(doc);
            }
        });
        return result;
    }

    private List<VehicleDocument> filterByDailyRentBetween(BigDecimal minDailyRent, BigDecimal maxDailyRent) {
        List<VehicleDocument> result = new ArrayList<>();
        vehicleStore.values().forEach(doc -> {
            if (doc.getDailyRent() != null && 
                doc.getDailyRent().compareTo(minDailyRent) >= 0 && 
                doc.getDailyRent().compareTo(maxDailyRent) <= 0) {
                result.add(doc);
            }
        });
        return result;
    }

    private List<VehicleDocument> filterBySeats(Integer seats) {
        List<VehicleDocument> result = new ArrayList<>();
        vehicleStore.values().forEach(doc -> {
            if (doc.getSeats() != null && doc.getSeats().equals(seats)) {
                result.add(doc);
            }
        });
        return result;
    }

    private List<VehicleDocument> filterByKeyword(String keyword) {
        List<VehicleDocument> result = new ArrayList<>();
        vehicleStore.values().forEach(doc -> {
            if ((doc.getName() != null && doc.getName().contains(keyword)) ||
                (doc.getBrand() != null && doc.getBrand().contains(keyword)) ||
                (doc.getModel() != null && doc.getModel().contains(keyword))) {
                result.add(doc);
            }
        });
        return result;
    }

    private List<VehicleDocument> filterByRecommended(Boolean recommended) {
        List<VehicleDocument> result = new ArrayList<>();
        vehicleStore.values().forEach(doc -> {
            if (doc.getRecommended() != null && doc.getRecommended().equals(recommended)) {
                result.add(doc);
            }
        });
        return result;
    }

    private List<VehicleDocument> filterByRatingBetween(Float minRating, Float maxRating) {
        List<VehicleDocument> result = new ArrayList<>();
        vehicleStore.values().forEach(doc -> {
            if (doc.getRating() != null && 
                doc.getRating() >= minRating && 
                doc.getRating() <= maxRating) {
                result.add(doc);
            }
        });
        return result;
    }

    private List<VehicleDocument> filterByYearBetween(Integer minYear, Integer maxYear) {
        List<VehicleDocument> result = new ArrayList<>();
        vehicleStore.values().forEach(doc -> {
            if (doc.getYear() != null && 
                doc.getYear() >= minYear && 
                doc.getYear() <= maxYear) {
                result.add(doc);
            }
        });
        return result;
    }
} 